#pragma once

#include <iostream>
#include <functional>
#include <string>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include "protocol.hpp"

#define BUF_NUM 1024

namespace tcps
{
    enum
    {
        USAGE = 1,
        SOCK_ERR,
        BIND_ERR,
        LISTEN_ERR
    };

    using func_t = std::function<bool(const request &, response *)>;

    class TcpServer;

    const std::string gip = "0.0.0.0";

    class ThreadData
    {
    public:
        ThreadData(TcpServer *td, int sock)
            : _this(td), _sock(sock)
        {
        }

    public:
        TcpServer *_this;
        int _sock;
    };

    class HttpServer
    {
    public:
        HttpServer(const uint16_t &serverport, func_t func)
            : _listensockfd(-1), _serverport(serverport), _func(func)
        {
        }
        void initHttpServer()
        {
            _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensockfd < 0)
                exit(SOCK_ERR);
            struct sockaddr_in local;
            bzero(&local, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_serverport);
            local.sin_addr.s_addr = INADDR_ANY;

            if (bind(_listensockfd, (struct sockaddr *)&local, sizeof(local)) != 0)
                exit(BIND_ERR);
            if (listen(_listensockfd, 4) != 0)
            {
                exit(LISTEN_ERR);
            }
        }
        void runHttpServer()
        {
            signal(SIGCHLD, SIG_IGN);
            for (;;)
            {
                struct sockaddr_in client;
                socklen_t clientlen = sizeof(client);
                int sock = accept(_listensockfd, (struct sockaddr *)&client, &clientlen);
                if (sock < 0)
                {
                    continue;
                }
                pid_t id = fork();
                if (id == 0)
                {
                    handlerHttpRequest(sock);
                    close(sock);
                }
            }
        }
        void handlerHttpRequest(int sock)
        {
            // 1. 先接收一个完整的请求
            // 2. 对请求进行反序列化
            // 3. 对请求进行处理
            // 4. 对响应进行序列化
            // 5. 将响应返回给客户端
            char buffer[4096];
            auto n = recv(sock, buffer, sizeof(buffer) - 1, 0);
            request req;
            response resp;
            if (n > 0)
            {
                buffer[n] = 0;
                req.inbuffer = buffer;
                req.parse();
                if (_func(req, &resp))
                {
                    send(sock, resp.outbuffer.c_str(), resp.outbuffer.size(), 0);
                }
            }
        }
        ~HttpServer()
        {
            close(_listensockfd);
        }

    private:
        std::string _serverip;
        uint16_t _serverport;
        int _listensockfd;
        func_t _func;
    };
}